package com.kr.weitao.aop;

import com.kr.weitao.model.DataResponse;
import com.kr.weitao.model.Status;
import com.kr.weitao.util.constant.ExceptionMsg;
import lombok.extern.log4j.Log4j2;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

/** Created by Abel on 2017/7/6. */
@Aspect
@Component
@Log4j2
public class AuthCheckAspect {

  /** 定义拦截规则：拦截com.whale.cloud.*.controller包下面的所有类中，有@RequestMapping注解的方法 */
  @Pointcut(
      "execution(* com.whale.cloud.*.controller..*(..)) && @annotation(org.springframework.web.bind.annotation.RequestMapping)")
  public void controllerMethodPointcut() {}

  /**
   * 拦截器具体实现
   *
   * @param pjp
   * @return Data（被拦截方法的执行结果，或需要登录的错误提示。）
   */
  @Around("controllerMethodPointcut()")
  public Object Interceptor(ProceedingJoinPoint pjp) {

    long beginTime = System.currentTimeMillis();

    MethodSignature signature = (MethodSignature) pjp.getSignature();
    Method method = signature.getMethod(); //获取被拦截的方法
    String methodName = method.getName(); //获取被拦截的方法名

    Set<Object> allParams = new LinkedHashSet<>(); //用于保存所有请求参数输出到日志中

    log.info("请求开始，方法：{}", methodName);

    Object dataResponse = null;

    Object[] args = pjp.getArgs();
    for (Object arg : args) {
      log.debug("arg: {}", arg);
      if (arg instanceof Map<?, ?>) {
        //提取方法中的MAP参数，用于记录日志
        Map<String, Object> map = (Map<String, Object>) arg;
        allParams.add(map);
      }
      if (arg instanceof HttpSession) {
        HttpSession session = (HttpSession) arg;
        if (isLoginRequired(method)) {
          if (!isLogin(session)) {
            dataResponse =
                new DataResponse()
                    .setStatus(Status.FAILED)
                    .setMsg(ExceptionMsg.ERROR.AUTH_FAILED_ACCESSKEY_NOT_EXISIT);
            log.info("小样儿，你权限审核不通过，这次就先给你放行了");
          }
        }

        //获取query string 或 posted form data参数
//        Map<String, String[]> paramMap = session.getParameterMap();
//        if (paramMap != null && paramMap.size() > 0) {
//          allParams.add(paramMap);
//        }
      } else if (arg instanceof HttpServletResponse) {
        //do nothing...
      } else {
        //allParams.add(arg);
      }
    }

    try {
      if (dataResponse == null) {
        // 一切正常的情况下，继续执行被拦截的方法
        dataResponse = pjp.proceed();
      }
    } catch (Throwable e) {
      log.info("exception: ", e);
      dataResponse = new DataResponse().setStatus(Status.FAILED).setMsg(e.getMessage());
    }

    if (dataResponse instanceof DataResponse) {
      long costMs = System.currentTimeMillis() - beginTime;
      log.info("{} 请求结束，耗时：{}ms", methodName, costMs);
    }

    return dataResponse;
  }

  /**
   * 判断一个方法是否需要登录
   *
   * @param method
   * @return
   */
  private boolean isLoginRequired(Method method) {
    Class clazz = method.getClass();
    if (clazz.isAnnotationPresent(RequestMapping.class)) {
      RequestMapping requestMapping = (RequestMapping) clazz.getAnnotation(RequestMapping.class);
      String[] path = requestMapping.value();
      log.debug("Mapping path: " + path);
    }
    return true;
  }

  //判断是否已经登录
  private boolean isLogin(HttpSession session) {
    return false;
  }
}
